package com.devops.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.model.*;
import com.devops.admin.po.DOSExportDataJobPo;
import com.devops.admin.service.*;
import com.devops.admin.mapper.DOSExportDataJobMapper;
import com.devops.admin.util.Assert;
import com.devops.admin.vo.DOSPageVo;
import com.devops.common.exception.DataValidateFiledException;
import com.devops.common.exception.MvcBusinessException;
import com.devops.constant.JobGroupEnum;
import com.devops.constant.ResourceSubTypeEnum;
import com.devops.admin.job.ExportDataJob;
import com.devops.admin.job.JobService;
import com.devops.shiro.vm.BaseUserVM;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author Dell
* @description 针对表【dos_export_data_job(导出数据任务)】的数据库操作Service实现
* @createDate 2023-12-25 16:39:19
*/
@Slf4j
@Service
public class DOSExportDataJobServiceImpl extends ServiceImpl<DOSExportDataJobMapper, DOSExportDataJob>
    implements DOSExportDataJobService{

    @Resource
    private DOSDynamicSQLService dosDynamicSQLService;
    @Resource
    DOSDatasourceService dosDatasourceService;
    @Resource
    private DOSResourceService dosResourceService;
    @Resource
    private JobService jobService;

    @Override
    public Boolean checkAndCreate(DOSExportDataJob exportDataJob) {
        check(exportDataJob);
        save(exportDataJob);
        return true;
    }

    @Override
    public Boolean checkAndUpdate(DOSExportDataJob exportDataJob) {
        Assert.isTrue(ObjectUtil.isNotNull(exportDataJob.getId()),"id不能为空");
        check(exportDataJob);
        DOSExportDataJob oldJob = getById(exportDataJob.getId());
        updateById(exportDataJob);
        if (oldJob.getActive() && !oldJob.getCronExpression().equals(exportDataJob.getCronExpression())) {
            try {
                Map<String, Object> dataMap = new HashMap<>(8);
                dataMap.put("jobId", exportDataJob.getId());
                jobService.restartJob(exportDataJob.getCronExpression(), ExportDataJob.class,
                        exportDataJob.getId().toString(),
                        JobGroupEnum.EXPORT_DATA.toString(), new JobDataMap(dataMap));
            } catch (SchedulerException e) {
                log.error(e.getMessage());
                throw new MvcBusinessException(e.getMessage());
            }
        }
        return true;
    }

    @Override
    public Boolean execute(Integer jobId) {
        try {
            Map<String, Object> dataMap = new HashMap<>(8);
            dataMap.put("jobId", jobId);
            BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
            String jobName = StrUtil.format("{}_{}_{}", jobId, user.getLoginName(), System.currentTimeMillis());
            jobService.executeJobNow(ExportDataJob.class, jobName,
                    JobGroupEnum.EXPORT_DATA.toString(), new JobDataMap(dataMap));
        } catch (SchedulerException e) {
            throw new RuntimeException("执行器执行失败");
        }
        return true;
    }

    @Override
    public TableResult<DOSExportDataJobPo> getExportDataJobList(DOSExportDataJob exportDataJob, DOSPageVo pageVo) {
        Page<DOSExportDataJobPo> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        List<DOSExportDataJobPo> list = baseMapper.getExportDataJobList(exportDataJob, page);
        TableResult<DOSExportDataJobPo> tableResult = new TableResult<>();
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setList(list);
        tableResult.setPagination(p);
        return tableResult;
    }

    @Override
    public DOSExportDataJobPo getExportDataJobPoById(Integer jobId) {
        DOSExportDataJob job = getById(jobId);
        DOSExportDataJobPo jobPo = new DOSExportDataJobPo();
        BeanUtil.copyProperties(job, jobPo);
        DOSResource db = dosResourceService.getById(jobPo.getResourceId());
        jobPo.setDbName(db.getName());
        jobPo.setDbType(db.getSubType());
        return jobPo;
    }

    @Override
    public Boolean startOrPauseExportDataJob(Integer jobId, Boolean active) {
        try {
            if (active) {
                DOSExportDataJob job = getById(jobId);
                Map<String, Object> dataMap = new HashMap<>(8);
                dataMap.put("jobId", jobId);
                jobService.startCronJob(job.getCronExpression(), ExportDataJob.class, jobId.toString(),
                        JobGroupEnum.EXPORT_DATA.toString(), new JobDataMap(dataMap));
            } else {
                jobService.stopJob(jobId.toString(), JobGroupEnum.EXPORT_DATA.toString());
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
            throw new MvcBusinessException(e.getMessage());
        }

        DOSExportDataJob exportDataJob = DOSExportDataJob.builder()
                .id(jobId)
                .active(active)
                .build();
        return updateById(exportDataJob);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean stopAndRemove(Integer jobId) {
        DOSExportDataJob job = getById(jobId);
        if (job.getActive()) {
            try {
                jobService.stopJob(jobId.toString(), JobGroupEnum.EXPORT_DATA.toString());
            } catch (SchedulerException e) {
                log.error(e.getMessage());
                throw new MvcBusinessException(e.getMessage());
            }
        }
        job.setActive(false);
        job.setVariables(null);
        updateById(job);
        return removeById(jobId);
    }

    private void check(DOSExportDataJob exportDataJob) throws RuntimeException {
        Assert.isTrue(StrUtil.isNotBlank(exportDataJob.getName()),"任务名称不能为空");
        Assert.isTrue(StrUtil.isNotBlank(exportDataJob.getSql()),"sql不能为空");
        Assert.isTrue(ObjectUtil.isNotNull(exportDataJob.getResourceId()),"数据源不能为空");

        DOSResource dosResource = dosResourceService.getById(exportDataJob.getResourceId());
        String expainSql;
        if (ResourceSubTypeEnum.ORACLE.getType().equals(dosResource.getSubType())) {
            expainSql = "EXPLAIN PLAN FOR " + exportDataJob.getSql();
            //我们的oracle从库无法分析执行计划
            return;
        } else {
            expainSql = "EXPLAIN " + exportDataJob.getSql();
        }
        try {
            dosDatasourceService.checkDB(dosResource.getName());
            dosDynamicSQLService.executeSql(dosResource.getName(), expainSql);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new DataValidateFiledException("sql测试不通过");
        }
    }
}




